//
//  MainViewController.m
//  SlashEM
//
//  Created by dirk on 12/30/09.
//  Copyright 2009 Dirk Zimmermann. All rights reserved.
//

//  This file is part of Slash'EM.
//
//  Slash'EM is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, version 2 of the License only.
//
//  Slash'EM is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with Slash'EM.  If not, see <http://www.gnu.org/licenses/>.

#import "MainViewController.h"
#import "NhYnQuestion.h"
#import "NhEvent.h"
#import "NhEventQueue.h"
#import "ZTouchInfoStore.h"
#import "ZTouchInfo.h"
#import "ZDirection.h"
#import "NhWindow.h"
#import "CommandButtonView.h"
#import "ZStack.h"
#import "NSString+Z.h"
#import "UIFactory.h"
#import "StringKeyTable.h"
#import "MenuView.h"
#import "ActionBar.h"
#import "NhMenuWindow.h"
#import "OverlayView.h"
#import "ZAction.h"
#import "NhCommand.h"
#import "NhTextInputEvent.h"
#import "ActionView.h"
#import "MapView.h"
#import "winiphone.h"

#include "func_tab.h"

#define kMinimumPinchDelta (10.0f)
#define kMinimumPanDelta (10.0f)

static MainViewController* instance;

@implementation MainViewController

+ (MainViewController *)instance {
	return instance;
}

#pragma mark UIKit

- (void)awakeFromNib {
	// responsible for viewDidLoad
	[super awakeFromNib];
	
	touchInfoStore = [[ZTouchInfoStore alloc] init];
	commands = [[ZStack alloc] init];
	overlayViews = [[ZStack alloc] init];
	actionBars = [[ZStack alloc] init];
	mapCenter = CGRectMake(0.0f, 0.0f, 40.0f, 40.0f);
	
	doubleTapDuration = 0.3f;
	
	instance = self;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

- (void)adjustCenterMap {
	CGRect mapBounds = ((MainView *) self.view).mapView.bounds;
	mapCenter.origin.x = (mapBounds.size.width-mapCenter.size.width)/2;
	mapCenter.origin.y = (mapBounds.size.height-mapCenter.size.height)/2;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
	[self adjustCenterMap];
}

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewIsSetup {
	[self adjustCenterMap];
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}

#pragma mark window API

- (void)refreshAllViews {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(refreshAllViews) withObject:nil waitUntilDone:NO];
	} else {
		// map is displayed by core, no need to do it here
		if (actionBars.count > 1) {
			UIView *v = [actionBars pop];
			[v removeFromSuperview];
			self.actionBarHidden = NO;
		}else if (actionBars.count == 0) {
			// first time, create main action bar
			[self mainActionBar];
		} else {
			[(ActionBar *) actionBars.peek update];
		}
		self.actionBarHidden = NO;
		[self refreshMessageView];
	}
}

- (void)refreshMessageView {
	[(MainView *) self.view refreshMessages];
}

- (void)handleDirectionQuestion:(NhYnQuestion *)q {
	NSArray *buttons = [NSArray arrayWithObjects:
						[NhCommand commandWithTitle:"Up" key:'<'],
						[NhCommand commandWithTitle:"Down" key:'>'],
						[NhCommand commandWithTitle:"Cancel" key:033],
						nil];
	[self pushActions:buttons];
}

// Parses the stuff in [] and returns the special characters like $-?* etc.
// examples:
// [$abcdf or ?*]
// [a or ?*]
// [- ab or ?*]
// [- or or ?*]
// [- a or ?*]
// [- a-cw-z or ?*]
// [- a-cW-Z or ?*]
- (void)parseYnChoices:(NSString *)lets specials:(NSString **)specials items:(NSString **)items {
	char cSpecials[BUFSZ];
	char cItems[BUFSZ];
	char *pSpecials = cSpecials;
	char *pItems = cItems;
	const char *pStr = [lets cStringUsingEncoding:NSASCIIStringEncoding];
	enum eState { start, inv, invInterval, end } state = start;
	char c, lastInv = 0;
	while (c = *pStr++) {
		switch (state) {
			case start:
				if (isalpha(c)) {
					state = inv;
					*pItems++ = c;
				} else if (!isalpha(c)) {
					if (c == ' ') {
						state = inv;
					} else {
						*pSpecials++ = c;
					}
				}
				break;
			case inv:
				if (isalpha(c)) {
					*pItems++ = c;
					lastInv = c;
				} else if (c == ' ') {
					state = end;
				} else if (c == '-') {
					state = invInterval;
				}
				break;
			case invInterval:
				if (isalpha(c)) {
					for (char a = lastInv+1; a <= c; ++a) {
						*pItems++ = a;
					}
					state = inv;
					lastInv = 0;
				} else {
					// never lands here
					state = inv;
				}
				break;
			case end:
				if (!isalpha(c) && c != ' ') {
					*pSpecials++ = c;
				}
				break;
			default:
				break;
		}
	}
	*pSpecials = 0;
	*pItems = 0;
	
	*specials = [NSString stringWithCString:cSpecials encoding:NSASCIIStringEncoding];
	*items = [NSString stringWithCString:cItems encoding:NSASCIIStringEncoding];
}

- (void)showYnQuestion:(NhYnQuestion *)q {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(showYnQuestion:) withObject:q waitUntilDone:NO];
	} else {
		[self hideKeyboard];
		[self refreshMessageView];
		if ([q.question containsString:@"direction"]) {
			[self handleDirectionQuestion:q];
		} else if (q.choices) {
			NSString *text = q.question;
			if (text && text.length > 0) {
				currentYnQuestion = q;
				UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Question" message:q.question
															   delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
				const char *pStr = q.choices;
				while (*pStr) {
					[alert addButtonWithTitle:[NSString stringWithFormat:@"%s", [StringKeyTable ynTitleFromChar:*pStr]]];
					pStr++;
				}
				[alert show];
			}
		} else {
			NSString *args = [q.question substringBetweenDelimiters:@"[]"];
			if (args) {
				NSString *choices = nil;
				NSString *items = nil;
				[self parseYnChoices:args specials:&choices items:&items];
				if (choices.length > 0) {
					const char *pStr = [choices cStringUsingEncoding:NSASCIIStringEncoding];
					NSMutableArray *buttons = [NSMutableArray array];
					char c;
					while (c = *pStr++) {
						char title[] = { c, '\0' };
						[buttons addObject:[NhCommand commandWithTitle:title key:c]];
					}
					[buttons addObject:[NhCommand commandWithTitle:"Cancel" key:033]];
					[self pushActions:buttons];
				}
			}
		}
	}
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
	if (alertView.numberOfButtons > 1) {
		char c = currentYnQuestion.choices[buttonIndex];
		[[NhEventQueue instance] addKey:c];
		currentYnQuestion = nil;
	} else {
		// add no-event
		[[NhEventQueue instance] addKey:-1];
	}
	[alertView release];
}

- (void)displayBlockingString:(NSString *)text {
	if (text && text.length > 0) {
		if (![NSThread isMainThread]) {
			[self performSelectorOnMainThread:@selector(displayBlockingString:) withObject:text waitUntilDone:NO];
		} else {
			UIAlertView *alert = nil;
			alert = [[UIAlertView alloc] initWithTitle:@"Message" message:text
											  delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
			[alert show];
		}
	}
}

- (void)displayBlockingWindow:(NhWindow *)w {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(displayBlockingWindow:) withObject:w waitUntilDone:NO];
	} else {
		if (w == [NhWindow mapWindow]) {
			[((MainView *) self.view).mapView setNeedsDisplay];
			[self pushActions:[NSArray arrayWithObject:[NhCommand commandWithTitle:"Ok" key:-1]]];
		} else if (w == [NhWindow messageWindow]) {
			// message window doesn't block
			[self refreshMessageView];
			// add no-event
			[[NhEventQueue instance] addKey:-1];
		} else {
			[self displayBlockingString:w.text];
		}
	}
}

- (void)displayWindow:(NhWindow *)w {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(displayWindow:) withObject:w waitUntilDone:NO];
	} else {
		if (w == [NhWindow messageWindow]) {
			[self refreshMessageView];
		} else if (w.type == NHW_MAP) {
			[((MainView *) self.view).mapView setNeedsDisplay];
		}
	}
}

- (void)cliparoundX:(int)x y:(int)y {
	[((MainView *) self.view).mapView cliparoundX:x y:y];
}

- (void)showMenuWindow:(NhMenuWindow *)w {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(showMenuWindow:) withObject:w waitUntilDone:NO];
	} else {
		[self disableInputs];
		MenuView *menuView = [[MenuView alloc] initWithFrame:[(MainView *) self.view bigSubviewFrame]];
		menuView.menuWindow = w;
		[overlayViews push:menuView];
		[self.view addSubview:menuView];
		[menuView release];
	}
}

- (void)getLine {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(getLine) withObject:nil waitUntilDone:YES];
	} else {
		NhEventQueue *queue = [NhEventQueue instance];
		if ([queue peek]) {
			char line[BUFSZ];
			char *pLine = line;
			while ([queue peek]) {
				NhEvent *e = [queue nextEvent];
				*pLine++ = e.key;
			}
			*pLine = '\0';
			NhTextInputEvent *te = [NhTextInputEvent eventWithText:[NSString stringWithCString:line encoding:NSASCIIStringEncoding]];
			[queue addEvent:te];
		} else {
			CGRect frame = [(MainView *) self.view textInputFrame];
			UITextField *textView = [[UITextField alloc] initWithFrame:frame];
			textView.autocorrectionType = UITextAutocorrectionTypeNo;
			textView.returnKeyType = UIReturnKeyDefault;
			textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
			textView.delegate = self;
			textView.clearButtonMode = UITextFieldViewModeWhileEditing;
			textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
			textView.borderStyle = UITextBorderStyleRoundedRect;
			[self.view addSubview:textView];
			[textView becomeFirstResponder];
			[textView release];
		}
	}
}

- (void)showExtendedCommands {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(showExtendedCommands) withObject:nil waitUntilDone:NO];
	} else {
		self.actionBarHidden = YES;
		CGRect frame = [(MainView *) self.view bigSubviewFrame];
		ActionView *actionView = [[ActionView alloc] initWithFrame:frame];
		NSMutableArray *actions = [[NSMutableArray alloc] init];
		for (int i = 0; extcmdlist[i].ef_txt != (char *)0; i++) {
			NhCommand *cmd = [NhCommand commandWithTitle:extcmdlist[i].ef_txt key:i];
			[actions addObject:cmd];
		}
		actionView.actions = actions;
		actionView.actionBar.actions = [NSArray arrayWithObject:
										[ZAction actionWithTitle:@"Cancel" target:self
														  action:@selector(cancelNhActionView:)]];
		[self.view addSubview:actionView];
		[overlayViews push:actionView];
		[actionView release];
	}
}

- (void)cancelNhActionView:(id)sender {
	[self cancelActionView:sender];
	[[NhEventQueue instance] addKey:-1];
}

- (void)cancelActionView:(id)sender {
	ZAction *action = sender;
	UIView *button = action.sender;
	UIView *overlay = button.superview.superview;
	[overlay removeFromSuperview];
}

- (void)showContextCommands {
	NSArray *actions = [NhCommand currentCommands];
	if (actions.count > 0) {
		self.actionBarHidden = YES;
		CGRect frame = [(MainView *) self.view bigSubviewFrame];
		ActionView *actionView = [[ActionView alloc] initWithFrame:frame];
		actionView.actions = actions;
		actionView.actionBar.actions = [NSArray arrayWithObject:
										[ZAction actionWithTitle:@"Cancel" target:self action:@selector(cancelActionView:)]];
		[self.view addSubview:actionView];
		[overlayViews push:actionView];
		[actionView release];
	}
}

#pragma mark touch handling

- (int)keyFromDirection:(e_direction)d {
	static char keys[] = "kulnjbhy\033";
	return keys[d];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	[touchInfoStore storeTouches:touches];
	if (touches.count == 1) {
		UITouch *touch = [touches anyObject];
		if (touch.tapCount == 2) {
			ZTouchInfo *ti = [touchInfoStore touchInfoForTouch:touch];
			NSTimeInterval touchDuration = touch.timestamp - touchInfoStore.singleTapTimestamp;
			if (touchDuration < doubleTapDuration) {
				ti.doubleTap = YES;
			}
		} else {
			touchInfoStore.singleTapTimestamp = touch.timestamp;
		}
	} else if (touches.count == 2) {
		NSArray *allTouches = [touches allObjects];
		UITouch *t1 = [allTouches objectAtIndex:0];
		UITouch *t2 = [allTouches objectAtIndex:1];
		CGPoint p1 = [t1 locationInView:self.view];
		CGPoint p2 = [t2 locationInView:self.view];
		CGPoint d = CGPointMake(p2.x-p1.x, p2.y-p1.y);
		initialDistance = sqrt(d.x*d.x + d.y*d.y);
	}
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	MapView *mapView = ((MainView *) self.view).mapView;
	if (touchInfoStore.count == touches.count) {
		if (touches.count == 1) {
			UITouch *touch = [touches anyObject];
			ZTouchInfo *ti = [touchInfoStore touchInfoForTouch:[touches anyObject]];
			if (!ti.pinched) {
				CGPoint p = [touch locationInView:mapView];
				CGPoint delta = CGPointMake(p.x-ti.currentLocation.x, p.y-ti.currentLocation.y);
				BOOL move = NO;
				if (!ti.moved && (abs(delta.x)+abs(delta.y) > kMinimumPanDelta)) {
					ti.moved = YES;
					move = YES;
				} else if (ti.moved) {
					move = YES;
				}
				if (move) {
					[mapView moveAlongVector:delta];
					ti.currentLocation = p;
					[mapView setNeedsDisplay];
				}
			}
		} else if (touches.count == 2) {
			for (UITouch *t in touches) {
				ZTouchInfo *ti = [touchInfoStore touchInfoForTouch:t];
				ti.pinched = YES;
			}
			NSArray *allTouches = [touches allObjects];
			UITouch *t1 = [allTouches objectAtIndex:0];
			UITouch *t2 = [allTouches objectAtIndex:1];
			CGPoint p1 = [t1 locationInView:mapView];
			CGPoint p2 = [t2 locationInView:mapView];
			CGPoint d = CGPointMake(p2.x-p1.x, p2.y-p1.y);
			CGFloat currentDistance = sqrt(d.x*d.x + d.y*d.y);
			if (initialDistance == 0) {
				initialDistance = currentDistance;
			} else if (currentDistance-initialDistance > kMinimumPinchDelta) {
				// zoom (in)
				CGFloat zoom = currentDistance-initialDistance;
				[mapView zoom:zoom];
				initialDistance = currentDistance;
				[mapView setNeedsDisplay];
			} else if (initialDistance-currentDistance > kMinimumPinchDelta) {
				// zoom (out)
				CGFloat zoom = currentDistance-initialDistance;
				[mapView zoom:zoom];
				initialDistance = currentDistance;
				[mapView setNeedsDisplay];
			}
		}
	}
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	[touchInfoStore removeTouches:touches];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	//NSLog(@"MainViewController.touchesEnded");
	MapView *mapView = ((MainView *) self.view).mapView;
	if (touches.count == 1) {
		UITouch *touch = [touches anyObject];
		ZTouchInfo *ti = [touchInfoStore touchInfoForTouch:[touches anyObject]];
		if (!ti.pinched && !ti.moved) {
			CGPoint pos = [touch locationInView:self.view];
			UIView *hitView = [self.view hitTest:pos withEvent:event];
			if (hitView == mapView) {
				int tx, ty; // for travel to and getpos
				pos = [touch locationInView:mapView];
				if (!mapView.panned) {
					CGRect posRect = CGRectMake(pos.x, pos.y, 0.0f, 0.0f);
					if (CGRectIntersectsRect(posRect, mapCenter)) {
						// center tap
						[self showContextCommands];
					} else {
						// direction movement
						if (!iphone_getpos) {
							CGPoint center = [mapView.superview convertPoint:mapView.center toView:mapView];
							CGPoint delta = CGPointMake(pos.x-center.x, -(pos.y-center.y));
							e_direction d = [ZDirection directionFromEuclideanPointDelta:&delta];
							int key = [self keyFromDirection:d];
							if (ti.doubleTap) {
								[[NhEventQueue instance] addEvent:[NhEvent eventWithKey:'g']];
							}
							[[NhEventQueue instance] addEvent:[NhEvent eventWithKey:key]];
						} else {
							[mapView tilePositionX:&tx y:&ty fromPoint:pos];
							[[NhEventQueue instance] addEvent:[NhEvent eventWithKey:0 mod:0 x:tx y:ty]];
						}
					}
				} else {
					// travel to
					[mapView tilePositionX:&tx y:&ty fromPoint:pos];
					//NSLog(@"travel %d,%d to %d,%d", u.ux, u.uy, tx, ty);
					[[NhEventQueue instance] addEvent:[NhEvent eventWithKey:0 mod:0 x:tx y:ty]];
					[mapView resetPanOffset];
				}
			}
		}
	}
	initialDistance = 0;
	[touchInfoStore removeTouches:touches];
}

#pragma mark UITextViewDelegate

- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
	return YES;
}

- (void)textViewDidEndEditing:(UITextView *)textView {
	// avoid EXC_BAD_ACCESS by scheduling
	[textView performSelectorOnMainThread:@selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
	const char *pStr = [text cStringUsingEncoding:NSASCIIStringEncoding];
	char c;
	while (c = *pStr++) {
		switch (c) {
			case '\n':
				[textView resignFirstResponder];
				break;
			default:
				[[NhEventQueue instance] addEvent:[NhEvent eventWithKey:c]];
				break;
		}
	}
	return YES;
}

#pragma mark UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
	[[NhEventQueue instance] addEvent:[NhTextInputEvent eventWithText:textField.text]];
	[textField resignFirstResponder];
	[textField removeFromSuperview];
	return YES;
}

#pragma mark commands

- (void)showKeyboardAction:(id)sender {
	UITextView *dummyTextView = [[UITextView alloc] initWithFrame:CGRectZero];
	dummyTextView.autocorrectionType = UITextAutocorrectionTypeNo;
	dummyTextView.returnKeyType = UIReturnKeyDone;
	dummyTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
	dummyTextView.delegate = self;
	[self.view addSubview:dummyTextView];
	[dummyTextView becomeFirstResponder];
	[dummyTextView release];
}

- (void)commandAction:(NhCommand *)cmd {
	[[NhEventQueue instance] addCommand:cmd];
}

- (void)helpMenuAction:(id)sender {
	self.actionBarHidden = YES;
	CGRect frame = [(MainView *) self.view bigSubviewFrame];
	ActionView *actionView = [[ActionView alloc] initWithFrame:frame];
	NSArray *actions = [NSArray arrayWithObjects:
						[NhCommand commandWithTitle:"What's here" key:':'],
						[NhCommand commandWithTitle:"What is" key:';'],
						[NhCommand commandWithTitle:"Help" key:'?'],
						nil];
	actionView.actions = actions;
	actionView.actionBar.actions = [NSArray arrayWithObject:
									[ZAction actionWithTitle:@"Cancel" target:self
													  action:@selector(cancelActionView:)]];
	[self.view addSubview:actionView];
	[overlayViews push:actionView];
	[actionView release];
}

#pragma mark util

- (void)hideKeyboard {
	if (self.view.isFirstResponder) {
		return;
	}
	for (UIView *view in self.view.subviews) {
		if (view.isFirstResponder) {
			[view resignFirstResponder];
		}
	}
}

- (void)setActionBarHidden:(BOOL)h {
	ActionBar *actionBar = (ActionBar *) [actionBars peek];
	if (h) {
		actionBar.hidden = YES;
	} else {
		// only show when there are no overlays present
		actionBar.hidden = (overlayViews.count != 0);
	}
}

- (BOOL)actionBarHidden {
	ActionBar *actionBar = (ActionBar *) [actionBars peek];
	return actionBar.hidden;
}

- (void)popOverlayView:(OverlayView *)v {
	[overlayViews pop];
	self.actionBarHidden = NO;
}

- (void)disableInputs {
	[self hideKeyboard];
	self.actionBarHidden = YES;
}

- (void)pushActions:(NSArray *)actions {
	self.actionBarHidden = YES;
	ActionBar *actionBar = [[ActionBar alloc] initWithFrame:[(MainView *)self.view actionBarFrame]];
	//NSLog(@"pushActions: %@", actionBar);
	[self.view addSubview:actionBar];
	actionBar.actions = actions;
	[actionBars push:actionBar];
	[actionBar release];
}

- (ActionBar *)mainActionBar {
	if (!actionBars.bottom) {
		NSArray *mainActions = [NSArray arrayWithObjects:
								[NhCommand commandWithTitle:"Wait" key:'.'],
								[NhCommand commandWithTitle:"Search" keys:"9s"],
								[ZAction actionWithTitle:@"abc"
												  target:[MainViewController instance] action:@selector(showKeyboardAction:)],
								[NhCommand commandWithTitle:"Inv" key:'i'],
								[NhCommand commandWithTitle:"Ext" key:'#'],
								[NhCommand commandWithTitle:"Re" key:C('a')],
								[ZAction actionWithTitle:@"?"
												  target:[MainViewController instance] action:@selector(helpMenuAction:)],
								[NhCommand commandWithTitle:"Fire" key:'f'],
								[NhCommand commandWithTitle:"Cast" key:'Z'],
								nil];
		ActionBar *mainActionBar = [[ActionBar alloc] initWithFrame:[(MainView *) self.view actionBarFrame]];
		mainActionBar.actions = mainActions;
		[self.view addSubview:mainActionBar];
		[actionBars push:mainActionBar];
		[mainActionBar release];
	}
	return [actionBars bottom];
}

#pragma mark called from other controls

- (void)removeActionBar:(ActionBar *)ab {
	//NSLog(@"removeActionBar: %@", ab);
	if (ab != self.mainActionBar) {
		[ab removeFromSuperview];
		self.actionBarHidden = NO;
		ActionBar *top = [actionBars pop];
		if (top != ab) {
			NSLog(@"action bar disorder!");
		}
	}
}

#pragma mark dealloc

- (void)dealloc {
	[touchInfoStore release];
	[commands release];
	[overlayViews release];
	[actionBars release];
    [super dealloc];
}

@end
